package com.ims.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baiwang.bop.client.BopException;
import com.baiwang.bop.client.ILoginClient;
import com.baiwang.bop.client.impl.PostLogin;
import com.baiwang.bop.request.impl.LoginRequest;
import com.baiwang.bop.respose.entity.LoginResponse;
import com.baiwang.open.client.login.BopLoginClient;
import com.baiwang.open.client.login.BopLoginResponse;
import com.baiwang.open.client.login.PasswordLoginClient;
import com.baiwang.open.client.login.PasswordLoginConfig;
import com.baiwang.open.entity.request.*;
import com.baiwang.open.entity.request.node.*;
import com.baiwang.open.entity.response.*;
import com.baiwang.open.exception.BWOpenException;
import com.ims.common.core.redis.RedisCache;
import com.ims.common.exception.base.BaseException;
import com.ims.common.utils.StringUtils;
import com.ims.common.utils.spring.SpringUtils;
import com.ims.core.doc.domain.TScSettleSalInvoice;
import com.ims.core.doc.vo.bwapi.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baiwang.open.client.BWRestClient;
import com.baiwang.open.client.IBWClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 百望接口工具
 *
 * @author IMS
 */
public class BaiwangUtils
{
    private static final Logger log = LoggerFactory.getLogger(BaiwangUtils.class);

    private static final String REDIS_KEY = "IMS_BAIWANG_TOKEN";

    @Autowired
    private static RedisCache redisCache;


    // private static String appId = BaiWangConfig.getAppId();
    private static String appId = "2635869897380331837";
    //  private static String appKey = BaiWangConfig.getAppKey();
    private static String appKey = "10059320";
    // private static String appSecret  = BaiWangConfig.getAppSecret();
    private static String appSecret  = "8a688d6c-2cd3-4757-90b1-3c9af0e28988";
    // private static String username  = BaiWangConfig.getUserName();
    private static String username  = "admin_ocso4lupbirrs";
    // private static String password  = BaiWangConfig.getPassword();
    private static String password  = "S10G388Uu";
    // private static String userSalt  = BaiWangConfig.getSalt();
    private static String userSalt  = "c557d15bfc764f24880bbd4ecdbc3340";
    private static String url  = "https://openapi.baiwang.com/router/rest";
    // private static String url  = BaiWangConfig.getUrl();
    // private static String url  = "https://sandbox-openapi.baiwang.com/router/rest";

    /**
     * 税号
     */
    private static String taxNo = "91310118632206381P";

    /**
     * 探活账号
     */
    private static String taxUserName = "";


    /**
     * 0. 获取token
     * @return
     */
    public static String getToken()
    {
        if(redisCache == null){
            redisCache = SpringUtils.getBean(RedisCache.class);
        }
        // redis查询百望token
        // String token ="6746de7b-7d87-4475-b313-84a4cf53356e";
        String token = redisCache.getCacheObject(REDIS_KEY);
        //  String token = "";
        if(!StringUtils.isEmpty(token)){
            log.info("缓存百望TOKEN:{}", token);
            return token;
        }
        log.info("begin 登陆----------");
        ILoginClient loginClient = new PostLogin(url);
        LoginRequest loginRequest = new LoginRequest();
        LoginResponse loginResponse = null;
        try {
            loginRequest.setAppkey(appKey);
            loginRequest.setAppSecret(appSecret);
            loginRequest.setUserName(username);
            loginRequest.setPasswordMd5(password);
            loginRequest.setUserSalt(userSalt);
            loginResponse = loginClient.login(loginRequest);
            log.info(loginResponse.getExpires_in() + "");
            log.info(loginResponse.getToken_type() + "");
            log.info(loginResponse.getScope() + "");
            log.info(loginResponse.getRefresh_token() + "");
            log.info(loginResponse.getAccess_token() + "");
            token = loginResponse.getAccess_token();
            log.info("百望用户{}的获取的token是：{}", username, token);
            // 缓存6小时
            redisCache.setCacheObject(REDIS_KEY, token,30, TimeUnit.MINUTES);
            return token;
        } catch (BopException e) {
            log.info("登录失败");
            log.info(e.getErrCode());
            log.info(e.getErrMsg());
            log.info(e.getMessage());
            log.error("获取百望token失败",e);
            throw new BaseException("获取百望token失败");
        }
    }

    /** ======================== 数电登录类接口 ======================== **/

    /**
     * 1. 探活
     * 如果返回无效用户，则需要调用 电票账密统一登录接口 ，传参operationType=1，创建该用户的数电账号
     * @return
     */
    public static ChannelLoginNewexploreactivityResponse exploReactivity(String taxNo, String areaCode)
    {
        // redis查询百望token
        String token = getToken();
        try {
            // 重载方法，可以传自定义请求唯一标识
            ChannelLoginNewexploreactivityRequest request = new ChannelLoginNewexploreactivityRequest();
            // 11、天津市：12、河北省：13、山西省：14、内蒙古省：15、辽宁省：21、大连市：91、吉林省：22、黑龙江省：23、
            // 上海市：31、江苏省：32、
            // 浙江省：33、宁波市：93、安徽省：34、福建省：35、厦门市：94、江西省：36、山东省：37、青岛市：92、河南省：41、湖北省：
            // 42、湖南省：43、广东省：44、深圳市：95、广西省：45、海南省：46、重庆市：50、四川省：51、贵州省：52、云南省：53、 西藏省：54、陕西省：61、甘肃省：62、青海省：63、宁夏省：64、新疆省：65
            request.setAreaCode(areaCode);
            // 税号
            request.setTaxNo(taxNo);
            // 业务类型：0开票，1用票 （值为0时需要传username）
            request.setBusinessType("1");
            // 用户名
            // request.setUsername("18321010206");

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ChannelLoginNewexploreactivityResponse response = client.channelLogin().newexploreactivity(request, token);
            // 重载方法，可以传自定义请求唯一标识
            log.info(response.toString());
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /**
     * 2. 全电连接器密码加密配置
     * @return
     */
    public static ChannelLoginEncryptconfigResponse encryptconfig()
    {
        // redis查询百望token
        String token = getToken();
        try {
            PasswordLoginConfig loginConfig = new PasswordLoginConfig();
            loginConfig.setUrl(url);
            loginConfig.setClientId(appKey);
            loginConfig.setClientSecret(appSecret);
            loginConfig.setUsername(username);
            loginConfig.setPassword(password);
            loginConfig.setUserSalt(userSalt);
            // 获取token, token相关说明请参考 文档中心 -> 用户授权说明
            ChannelLoginEncryptconfigRequest request = new ChannelLoginEncryptconfigRequest();
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ChannelLoginEncryptconfigResponse response = client.channelLogin().encryptconfig(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }


    /**
     * 3. 电票账密统一登录接口
     * @return
     */
    public static ChannelLoginQuickuniteResponse login(String phone, String taxNo, String areaCode, String deepChar)
    {
        // redis查询百望token
        String token = getToken();
        try {
            PasswordLoginConfig loginConfig = new PasswordLoginConfig();
            loginConfig.setUrl(url);
            loginConfig.setClientId(appKey);
            loginConfig.setClientSecret(appSecret);
            loginConfig.setUsername(username);
            loginConfig.setPassword(password);
            loginConfig.setUserSalt(userSalt);
            ChannelLoginQuickuniteRequest request = new ChannelLoginQuickuniteRequest();
            request.setAreaCode(areaCode);
            request.setEncryptVersion("ENCRYPT_VERSION_20230703");
            request.setOperationType("");
            request.setAuthenticationType("0");
            request.setTaxNo(taxNo);
            // 业务类型：开票：0、用票：1，不传参默认0
            request.setBusinessType("0");
            // 身份字典：办税员：1、开票员：2、财务负责人：3、法定代表人：4、其他 ：99
            request.setLoginIdentity("1");
            // 所属业务：开票 ：01；用票：10；开用票：11。 FIXME 此处是否与 BusinessType 业务类型：开票：0、用票：1，冲突？
            request.setAffiliatedBusiness("11");
            request.setDeepChar(deepChar);
            request.setUsername(phone);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ChannelLoginQuickuniteResponse response = client.channelLogin().quickunite(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            // batchNo:fe3c5c997d68426f8e6ee61b5d47d695_CALLBACK, msg:本税号和账号已登录，请勿重复操作
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }


    /**
     * 4. 需手机验证码登录省份，调用接口baiwang.channel.login.quickunite成功并收取到手机验证码后
     * ，调用本接口进行最终登录
     * @return
     */
    public static ChannelLoginSmscodeResponse smscode(String smscode, String batchNo)
    {
        // redis查询百望token
        String token = getToken();
        try {
            PasswordLoginConfig loginConfig = new PasswordLoginConfig();
            loginConfig.setUrl(url);
            loginConfig.setClientId(appKey);
            loginConfig.setClientSecret(appSecret);
            loginConfig.setUsername(username);
            loginConfig.setPassword(password);
            loginConfig.setUserSalt(userSalt);
            BopLoginClient loginClient = new PasswordLoginClient(loginConfig);
            ChannelLoginSmscodeRequest request = new ChannelLoginSmscodeRequest();
            request.setBatchNo(batchNo);
            request.setCode(smscode);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ChannelLoginSmscodeResponse response = client.channelLogin().smscode(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /** ======================== 销项发票开具接口 ======================== **/

    /**
     * 5. 发票开具
     * @return
     */
    public static OutputInvoiceIssueResponse invoiceIssue(InvoiceForIssue invoiceForIssue)
    {
        // 判断发票状态，只有待开的发票才能开票
//        if(!invoiceForIssue.getProcessStatus().equals(ProcessStatus.PENDING_INVOICING.getCode())){
//            throw new ServiceException("发票" + invoiceForIssue.getInvoiceCode() + "不是待开票状态，无法操作");
//        }
        // 获取百望token
        String token = getToken();
        try {
            OutputInvoiceIssueRequest request = new OutputInvoiceIssueRequest();
            // 否	超过发票单张限额是否需要拆分开具，默认不拆分（拆分只支持发票类型代码为 专票 004 普票 007 电子票 026的发票）
            // request.setIsSplit(false);
            // 否	是否返回蓝票已红冲红票信息，0否，1是，默认为0（仅支持税控发票）
            // request.setIsReturnRedInfo("1");
            // 否	值为（1/0 1 需要补全 0不需要补全，默认为0）是否根据客户编码，购方税号，购方名称查询客户信息补全未填写的购方信息
            // （购方税号，购方名称，购方地址电话，购方银行账号，邮箱，手机）
            // request.setCompletionCustom("0");
            // 是
            OutputInvoiceIssuePreInvoice data = new OutputInvoiceIssuePreInvoice();
                // 否	整单折扣率（数电发票暂不支持）,取值[1-100]正整数
                // data.setDiscountRate(0);
                // 60	否	红字信息表UUID，开具全电负数发票必传
                // data.setRedConfirmUuid("");
                // 100	否	购方开户行及账号， 增值税专用发票开具时必填，发票类型代码为01、02时该字段拆分为银行名称、账号两个字段
                data.setBuyerBankAccount(invoiceForIssue.getBuyerBank() + " " + invoiceForIssue.getBuyerAccount());
                //? 100	否	客户邮箱 取收票人邮箱
                data.setBuyerEmail(invoiceForIssue.getCollectMail());
                // 13	否	合计税额， 保留两位小数；支持价税分离 =取发票税额
                data.setInvoiceTotalTax(invoiceForIssue.getTax());
                // 否	购方自然人标记Y:自然人； N:非自然人，默认为N
                // data.setBuyerNaturalPerson("N");
                // 20	否	整单折扣金额（数电发票暂不支持）,大于0小于发票总金额，如果是含税发票，大于0小于含税总金额
                // data.setDiscountAmount(BigDecimal.valueOf(0.0));
                // 20	否	证件类型，201:居民身份证;208:外国护照;210:港澳居民来往内地通行证;213:台湾居民来往大陆通行证;215:外国人居留证;219:香港永久性居民身份证;220:台湾身份证;221:澳门特别行政区永久性居民身份证;233:外国人永久居留身份证(外国人永久居留证);103:税务登记证;299:其他个人证件，特殊票种标识为24时必填
                // data.setCredentialsType("");
                // 200	否	销方地址，发票类型代码为01、02时该字段可用
                data.setSellerAddress(invoiceForIssue.getSellerAddress());
                // 16	否	复核人， 16个字符；税控开具时： 为空时，如果终端有值取终端，如果没有去机构获取，若都没有则为空！全电类开具时：此字段非必填，即发票类型代码为01，02时该字段非必填
                data.setChecker(invoiceForIssue.getReviewName());
                // 否	征税方式， 0：普通征税；2：差额征税（默认是0普通征税）
                // data.setTaxationMethod("0");
                // 20	否
                // 红字信息表/确认单编号，仅invoiceType=1时需要传入数据 税控类红票开具时，invoiceTypeCode=004、028时必须传值，传入红字信息表编号； 全电类红票开具时，invoiceTypeCode=01、02时必须传值，传入红字确认单编号；
                // data.setRedInfoNo("");
                // 16	否	收款人， 16个字符；税控类开具时：若为空，如果终端有值取终端，如果没有去机构获取，若都没有则为空；全电类开具时：此字段非必填，即发票类型代码为01，02时该字段非必填
                data.setPayee(invoiceForIssue.getCollectName());
                // 2	否	减按征税标识，01：个人出租住房；03：销售自己使用过的固定资产；05：住房租赁。默认为空,空代表无。
                // data.setReducedTaxCode("");
                // 80	否	购买方地址，发票类型代码为01、02时该字段可用
                data.setBuyerAddress(invoiceForIssue.getBuyerAddress());
                // 2	否	差额征税标签：01 全额开票、 02 差额开票 ；发票类型代码为01，02时且征税方式为2必填
                // data.setTaxationLabel("01");
                // 150	否	第三方系统名称
                // data.setSystemName("");
                // 32	否	开票类型 0:正数发票（蓝票） 1：负数发票（红票）默认0
                data.setInvoiceType("0");
                // 10	否	红冲原因（1 销货退回 2 开票有误 3 服务终止 4 销售折让）税控红冲原因：建议按实际开票情况传入红冲原因，若不传系统会自动根据情况判断并赋值；全电红冲原因：必填
                // data.setRedIssueReason("");
                // 否	购方地址和联系电话是否显示在备注，true：购方地址和联系电话显示在备注，false：购方地址和联系电话不显示在备注
                // data.setDisplayBuyerAddTel(false);
                // 100	否	抄送人邮箱,多个用英文逗号隔开,最多5个抄送人信息 全电字符长度为200
                // data.setEmailCarbonCopy("");
                Map<String, Object> ext = new HashMap<String, Object>();
                // data.setExt(ext);
                // 50	否	发票请求流水号
                // data.setOrderNo("");
                // 20	否	购方单位税号， invoiceTypeCode=004、028、01（增值税专用发票、增值税电子专用发票、全电发票（增值税专用发票））开具时必传 invoiceSpecialMark=16|17（农产品收购、光伏收购）开具时必传
                data.setBuyerTaxNo(invoiceForIssue.getBuyerNumber());
                // 2	否	报废产品收购1%转3%放弃优惠开具理由，2：前期已开具3%征收率的发票，发生销售折让、中止或者退回等情形需要开具3%征收率的红字发票，或者开票有误需要重新开具3%征收率的发票；3：因为实际经营业务需要，放弃享受减按1%征收率征收增值税政策:，不填时系统默认按3处理。
                // data.setTaxReason("");
                // 2	否	成品油单价过低是否确认开具标识：Y 是； N 否 为空时默认值为N （备注：专票单价过低强制开票会记入异常发票，红冲需要在电子税务局申请解除然后再红冲；普票单价过低开具成功发票可以正常红冲）
                // data.setIsConfirmIssue("");
                // 50	否	合同号
                data.setContractNumber(invoiceForIssue.getContractNumber());
                // 8	否	原发票号码， invoiceType=1，税控负数普票开具时必传；红票选数电票时，此项可为空。
                // data.setOriginalInvoiceNo("");
                // 0：无清单；1：带清单（专普票发票明细大于等于8行必须带清单）：大于8行必须为清单票(电子票只能为非请单票)（默认是0无清单），发票类型代码为01，02时该字段无
                // data.setInvoiceListMark("0");
                // 50	是 开票流水号， 唯一标志开票请求。支持数字字母下划线组合。
                // 需注意，对开具失败的单据重新开具，这个流水号不能变，否则我们认为是新的单据开具，可能导致重复开票。
                data.setSerialNo(invoiceForIssue.getApplyNo());
                // 50	否	凭证号
                data.setVoucherNo(invoiceForIssue.getVoucherNumber());
                // 否	销方开户行银行账号是否显示在备注。true：销方开户行银行账号显示在备注，或者false：销方开户行银行账号不显示在备注
                // data.setDisplaySeller(false);
                // 40	否	客户电话
                // data.setBuyerPhone(invoiceForIssue.getBuyerTel());
                // 1	否	税局二次确认是否继续开票，1：是；0：否；（03建筑服务发票，建筑服务发生地和销方注册地址不同时是否继续开票,24报废产品收购需要缴纳购置税的提示是否继续开具），若不传值，系统默认按照“是”处理;
                // data.setConfirmIssue("1");
                // 13	否	合计金额， 保留两位小数；支持价税分离
                data.setInvoiceTotalPrice(invoiceForIssue.getFeeWithoutTax());
                // 30	否	用户账号，用于个人维度数据标记
                // data.setUserAccount("");
                    List<OutputInvoiceIssueInvoiceDetail> invoiceDetailsList = new ArrayList<OutputInvoiceIssueInvoiceDetail>();
                    int goodsLineNo = 1;
                    for(InvoiceEntryForIssue invoiceEntryForIssue : invoiceForIssue.getInvoiceEntryForIssueList()){
                        OutputInvoiceIssueInvoiceDetail outputInvoiceIssueInvoiceDetail = new OutputInvoiceIssueInvoiceDetail();
                         Map<String, Object> extDetail = new HashMap<String, Object>();
                        outputInvoiceIssueInvoiceDetail.setExt(extDetail);
                        // 5	是	税率,超长自动保留三位小数
                        outputInvoiceIssueInvoiceDetail.setGoodsTaxRate(invoiceEntryForIssue.getTaxRate().divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP));
                        // 否	发票行性质， 0：正常行；1：折扣行；2：被折扣行，默认为0
                        outputInvoiceIssueInvoiceDetail.setInvoiceLineNature("0");
                        // 	13	是	金额，小数点后2位,超长自动保留两位小数
                        outputInvoiceIssueInvoiceDetail.setGoodsTotalPrice(invoiceEntryForIssue.getAmount().setScale(2, RoundingMode.HALF_UP));
                        // 1	否	是否使用优惠政策， 0：未使用；1：使用 根据商品信息获取
                        // outputInvoiceIssueInvoiceDetail.setPreferentialMarkFlag("0");
                        // 50	否	商品编码， 可以支持根据商品名称或商品编码进行获取【增加商品编码字段】：平台必须维护商品信息
                        // outputInvoiceIssueInvoiceDetail.setGoodsPersonalCode("");
                        // 4	否	对应蓝票明细行号 税控类红字发票开具时无需传值； 全电类红字发票开具时必须传值；
                        // outputInvoiceIssueInvoiceDetail.setOriginalInvoiceDetailNo("");
                        // 36	否	规格型号，如果特殊票种为03、09、05、06，字段填写无效；特殊票种为15和31时填写车架号/车辆识别号；
                        outputInvoiceIssueInvoiceDetail.setGoodsSpecification(invoiceEntryForIssue.getSpecificatCode());
                        // 13	否	商品单价，最多允许17位（含小数点），小数点后最多允许13位，特殊票种为12时必填 乐企：单位、数量、单价应同时为空或同时不为空；rpa : 01 成品油发票 必填；如果特殊票种为03时，字段填写无效；特殊票种为稀土时，单价数量应该同时不为空。
                        outputInvoiceIssueInvoiceDetail.setGoodsPrice(invoiceEntryForIssue.getPrice());
                        // 1	否	零税率标识：空 代表不使用零税率； 1：出口免税和其他免税优惠政策； 2：不征增值税；3：普通零税率
                        outputInvoiceIssueInvoiceDetail.setFreeTaxMark("");
                        // 20	否	明细行折扣金额,全电不支持该字段
                        // outputInvoiceIssueInvoiceDetail.setGoodsDiscountAmount(tSalInvoiceEntry.get);
                        // 14	否	商品数量，最多允许17位（含小数点和负号），小数点后最多允许13位，特殊票种为05（不动产销售服务发票）、06（不动产租赁服务发票）、12（机动车）、01 （全电成品油发票）时必填；乐企：单位、数量、单价应同时为空或同时不为空；如果特殊票种为03时，字段填写无效；特殊票种为稀土时，单价数量应该同时不为空。
                        outputInvoiceIssueInvoiceDetail.setGoodsQuantity(invoiceEntryForIssue.getQty());
                        // 14	否	计量单位 特殊票种为12时必填,只能为辆 乐企：单位、数量、单价应同时为空或同时不为空；rpa：01 成品油发票必填 只能为吨或升；特殊票种为稀土时必填，只能为公斤或吨；如果特殊票种为03、09、05、06时，字段填写无效；代收车船税发票必填，只能为辆；电子烟发票必填，只能为盒；卷烟发票必填，卷烟生产企业开具卷烟发票单位必须为“万支”；卷烟批发企业开具卷烟发票 的单位必须为“标准条”或“支”；
                        outputInvoiceIssueInvoiceDetail.setGoodsUnit(invoiceEntryForIssue.getUnit());
                        // 13	否	税额，小数点后2位,超长自动保留两位小数， 如果为空，根据金额、税率计算得出
                        // outputInvoiceIssueInvoiceDetail.setGoodsTotalTax(invoiceEntryForIssue.getTax().setScale(2, RoundingMode.HALF_UP));
                        // 40	否	税收分类编码（末级节点）
                        outputInvoiceIssueInvoiceDetail.setGoodsCode(invoiceEntryForIssue.getTaxCode());
                        // 100	否	商品名称， 支持根据商品或商品编码获取商品信息：平台必须维护商品信息   ～～二选一必填
                        outputInvoiceIssueInvoiceDetail.setGoodsName(invoiceEntryForIssue.getTaxName());
                        // 4	是	明细行号
                        outputInvoiceIssueInvoiceDetail.setGoodsLineNo(goodsLineNo++);
                        // 200	否	优惠政策类型，preferentialMarkFlag=1，使用优惠政策时必传，如“免税”、“50%先征后退”、“即征即退50%”等
                        // outputInvoiceIssueInvoiceDetail.setVatSpecialManagement("");
                        invoiceDetailsList.add(outputInvoiceIssueInvoiceDetail);
                    }

                data.setInvoiceDetailsList(invoiceDetailsList);
                // 80	否	销方银行名称，发票类型代码为01、02时该字段可用
                data.setSellerBankName(invoiceForIssue.getSellerBank());
                // 否	购方开户行银行账号是否显示在备注，true：购方开户行银行账号显示在备注，或者false：购方开户行银行账号不显示在备注
                // data.setDisplayBuyer(false);
                // data.setDrawerCredentialsType("");
                // 12	否	原发票代码， invoiceType=1，税控负数普票开具时必传；红票选数电票时，此项可为空。
                // data.setOriginalInvoiceCode("");
                // 否	N：无共同购买方，Y：有共同购买方，传Y时共同购买方信息字段必填；不传默认按N处理；不支持乐企
                // data.setMulPurchaserMark("");
                // 20	否	销方电话，发票类型代码为01、02时该字段可用
                data.setSellerTelphone(invoiceForIssue.getSellerTel());
                // 选择纸质发票标志为Y时，纸票类型必填。
                // 票种为 普通发票02时可传： 04 2016版增值税普通发票（二联折叠票）， 05 2016版增值税普通发票（五联折叠票);
                // 票种为 增值税专用发票01可传： 1130 增值税专用发票（中文三联无金额限制版） ，1140 增值税专用发票（中文四联无金额限制版） 1160 增值，
                // 税专用发票（中文六联无金额限制版） ，1170 增值税专用发票（中文七联无金额限制版）
                // data.setPaperInvoiceTypeCode("");
                // 含税标志， 0：不含税；1：含税（默认不含税）
                data.setPriceTaxMark("1");
                // 20	否	购买方电话，发票类型代码为01、02时该字段可用
                data.setBuyerTelphone(invoiceForIssue.getBuyerTel());
                // 数电纸质发票标志，Y：是，N：否。税控类发票开具不校验此字段；暂只支持用数电电票红冲数电纸票
                // data.setPaperInvoiceFlag("N");
                    // 全电发票差额扣除额凭证明细，当征税方式为：差额征税-差额开票时必填
//                    List<OutputInvoiceIssueInvoiceBalanceinfo> invoiceBalanceinfoList = new ArrayList<OutputInvoiceIssueInvoiceBalanceinfo>();
//                    OutputInvoiceIssueInvoiceBalanceinfo outputInvoiceIssueInvoiceBalanceinfo = new OutputInvoiceIssueInvoiceBalanceinfo();
                    // 20	否	凭证号码
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceVoucherNo("");
//                    // 10	是	凭证类型：01 全电发票、02 增值税专用发票、03 增值税普通发票、04 营业税发票、05 财政票据、06 法院裁决书、07 契税完税凭证、08 其他发票类、09 其他扣除凭证
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceType("01");
//                    // 13	是	本次扣除金额
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceDeductAmount(BigDecimal.valueOf(10.0));
//                    // 10	是	序号
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceNo("1");
//                    // 20	否	开具日期：凭证类型为01、02、03、04时必填
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceIssueDate("2023-01-22");
//                    // 8	否	发票号码：凭证类型为02、03、04时必填
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceInvoiceNo("");
//                    // 13	是	凭证合计金额
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceTotalAmount(BigDecimal.valueOf(20.0));
//                    // 13	是	本次扣除金额
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceSource("0");
//                    // 30	否	全电发票号码：凭证类型为01时必填
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceElectricNo("");
//                    // 12	否	发票代码：凭证类型为02、03、04时必填
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceInvoiceCode("");
//                    // 100	否	备注：当凭证类型为08 其他发票类、09 其他扣除凭证时，备注必填。
//                    outputInvoiceIssueInvoiceBalanceinfo.setBalanceRemarks("\u5907\u6CE8");
//                    //
//                    invoiceBalanceinfoList.add(outputInvoiceIssueInvoiceBalanceinfo);
//                data.setInvoiceBalanceinfoList(invoiceBalanceinfoList);
                // 否	销方地址和联系电话是否显示在备注，true：销方地址和联系电话显示在备注，false：销方地址和联系电话不显示在备注
                data.setDisplaySellerAddTel(false);
                // 10	否	卷式发票票样 01 02 03 04 05 06 07
                // data.setMainGoodsName("");
                // data.setDrawerCredentialsNo("");
                // 100	否	销方地址及电话，发票类型代码为01、02时该字段拆分为地址、电话两个字段
                data.setSellerAddressPhone(invoiceForIssue.getSellerAddress() + " " + invoiceForIssue.getSellerTel());

                    // 否	List<OutputInvoiceIssueCoPurchaseInfo>, 共同购买方标识传Y时共同购买方明细字段必填
                    List<OutputInvoiceIssueCoPurchaseInfo> mulPurchaserList = new ArrayList<OutputInvoiceIssueCoPurchaseInfo>();
                    OutputInvoiceIssueCoPurchaseInfo outputInvoiceIssueCoPurchaseInfo = new OutputInvoiceIssueCoPurchaseInfo();
                    // 00	否	共同购买方传Y时，必填
                    // outputInvoiceIssueCoPurchaseInfo.setPurchaser("");
                    // 20	否	共同购买方传Y时，必填
                    // outputInvoiceIssueCoPurchaseInfo.setCertificateNo("");
                    // 2	否	共同购买方传Y时，必填。
                    // 101:组织机构代码证102:营业执照103:税务登记证199:其他单位证件201:居民身份证202:军官证203:武警警官证
                    // 204:士兵证205:军队离退休干部证206:残疾人证207:残疾军人证（1-8级）208:外国护照210:港澳居民来往内地通行证
                    // 212:中华人民共和国往来港澳通行证213:台湾居民来往大陆通行证214:大陆居民往来台湾通行证215:外国人居留证
                    // 216:外交官证217:使（领事）馆证218:海员证219:香港永久性居民身份证220:台湾身份证221:澳门特别行政区永久性居民身份证
                    // 222:外国人身份证件223:就业失业登记证224:退休证225:离休证227:中国护照228:城镇退役士兵自谋职业证229:随军家属身份证明
                    // 230:中国人民解放军军官转业证书231:中国人民解放军义务兵退出现役证232中国人民解放军士官退出现役证233:外国人永久居留身份证（外国人永久居留证）
                    // 234:就业创业证235:香港特别行政区护照236:澳门特别行政区护照237:中华人民共和国港澳居民居住证238:中华人民共和国台湾居民居住证
                    // 239:中华人民共和国外国人工作许可证》（A类）240:《中华人民共和国外国人工作许可证》（B类）241:《中华人民共和国外国人工作许可证》（C类）
                    // 291:出生医学证明299:其他个人证件
                    // outputInvoiceIssueCoPurchaseInfo.setCertificateType("");
                    mulPurchaserList.add(outputInvoiceIssueCoPurchaseInfo);
                // data.setMulPurchaserList(mulPurchaserList);
                // 80	否	购买方银行名称，发票类型代码为01、02时该字段可用
                data.setBuyerBankName(invoiceForIssue.getBuyerBank());
                // 10	否	整单折扣类型（数电发票暂不支持） 1 :按折扣金额价内折扣,2:按折扣金额价外折扣,3:按折扣率价内折扣,4:按折扣率价外折扣
                // data.setDiscountType("");
                // 100	否	购方地址及电话， 增值税专用发票开具时必填，发票类型代码为01、02时该字段拆分为地址电话两个字段
                data.setBuyerAddressPhone( invoiceForIssue.getBuyerAddress() + " " + invoiceForIssue.getBuyerTel());
                // 50	否	第三方系统id
                // data.setSystemId("");
                // 13	否	扣除额， taxationLabel=2，差额征税时必传。数值必须小于价税合计。
                // data.setDeductibleAmount(BigDecimal.valueOf(0.0));
                // 20	否	开票人，税票选填，
                // 取值逻辑：如果终端有值取终端，如果没有去机构获取，如果都没有会自动获取机构下随机用户名称；数电票Web连接器选填，取值逻辑：taxUserName＞drawer＞默认开票人＞终端授权开票人，如果以上四处都未取到随机获取该税号下最近一次登录的数电账号对应的开票人；数电票乐企连接器必填，长度最大300字符。
                data.setDrawer(invoiceForIssue.getInvoiceName());
                // 20	否	购方单位税号， invoiceTypeCode=004、028、01（增值税专用发票、增值税电子专用发票、全电发票（增值税专用发票））开具时必传 invoiceSpecialMark=16|17（农产品收购、光伏收购）开具时必传
                data.setInvoiceSpecialMark("00");
                // 80	是	购方单位名称 全电为100个字符
                data.setBuyerName(invoiceForIssue.getBuyerName());
                // 否	List<OutputInvoiceIssueAdditionalDetail>, 附加要素列表
//                List<OutputInvoiceIssueAdditionalDetail> additionalDetails = new ArrayList<OutputInvoiceIssueAdditionalDetail>();
//                OutputInvoiceIssueAdditionalDetail outputInvoiceIssueAdditionalDetail = new OutputInvoiceIssueAdditionalDetail();
                // 200	否	附加要素唯一编码（不可重复）
//                outputInvoiceIssueAdditionalDetail.setFieldKey("");
//                // 200	否	附加要素名称
//                outputInvoiceIssueAdditionalDetail.setFieldTitle("");
//                // 200	否	附加要素类型：date（日期）、input（文本）、inputnumber（数值）
//                outputInvoiceIssueAdditionalDetail.setFieldType("");
//                // 200	否	附加要素值，当为日期类型时，格式为yyyyy-MM-dd（年-月-日）
//                outputInvoiceIssueAdditionalDetail.setFieldValue("");
//                additionalDetails.add(outputInvoiceIssueAdditionalDetail);
//                data.setAdditionalDetails(additionalDetails);
                // 13	否	价税合计， 保留两位小数；支持价税分离
                data.setInvoiceTotalPriceTax(invoiceForIssue.getFee().setScale(2, RoundingMode.HALF_UP));
                // data.setAccessPlatformNo("");
                // 50	否	销方银行账号，发票类型代码为01、02时该字段可用
                data.setSellerBankNumber(invoiceForIssue.getSellerAccount());
                // 50	否	购买方银行账号，发票类型代码为01、02时该字段可用
                data.setBuyerBankNumber(invoiceForIssue.getBuyerAccount());
                // 100	否	销方开户行及账号，发票类型代码为01、02时不用此字段
                data.setSellerBankAccount(invoiceForIssue.getSellerBank() + " " + invoiceForIssue.getSellerTel());
                // 3	是	发票类型代码,
                // 004：增值税专用发票；
                // 007：增值税普通发票；
                // 026：增值税电子发票；
                // 025：增值税卷式发票；
                // 028:增值税电子专用发票
                // 01:全电发票(增值税专用发票)
                // 02:全电发票(普通发票)
                data.setInvoiceTypeCode(invoiceForIssue.getInvoiceType());
                    // 否	List<OutputInvoiceIssueInvoiceSpecialInfo>, List, 特定业务信息节点，当特殊票种标志为03、04、05、06、07时必填；当特殊票种标志为09时特定要素信息字段必须同时为空或同时不为空；
                    // List<OutputInvoiceIssueInvoiceSpecialInfo> invoiceSpecialInfoList = new ArrayList<OutputInvoiceIssueInvoiceSpecialInfo>();
                    // OutputInvoiceIssueInvoiceSpecialInfo outputInvoiceIssueInvoiceSpecialInfo = new OutputInvoiceIssueInvoiceSpecialInfo();
                    // 10	是	不动产租赁-租赁期止；yyyy-MM-dd
                    // outputInvoiceIssueInvoiceSpecialInfo.setLeaseHoldDateEnd("");
                    // 28	否	不动产销售服务-不动产单元代码，不可与网签合同备案编号同时填写；
                    // outputInvoiceIssueInvoiceSpecialInfo.setPropertyContractNo("");
                    // 120	是	建筑服务特定要素-建筑服务发生地，按照省、市、区/县三级传值，以&符间隔，举例“北京市&东城区、河北省&石家庄市&正定县”(建筑服务发生地和详细地址之和为120)
                    // outputInvoiceIssueInvoiceSpecialInfo.setBuildingLocalAddress("");
                    // 40	条件必填	代收车船税特定要素-保险单号，当特殊票种标志为07时必填。
                    // outputInvoiceIssueInvoiceSpecialInfo.setPolicyNumber("");
                    // 8	是	建筑服务特定要素-跨地（市）标志；标志：Y：是；N：否
                    // outputInvoiceIssueInvoiceSpecialInfo.setBuildingCrossSign("");
                    // 20	是	出行日期； yyyy-MM-dd
                    // outputInvoiceIssueInvoiceSpecialInfo.setCarriageDateYmd("");
                    // 40	否	底盘号/机架号
                    // outputInvoiceIssueInvoiceSpecialInfo.setTractorVehicleNo("");
                    // 8	是	不动产销售服务-跨地（市）标志；标志：Y：是；N：否
                    // outputInvoiceIssueInvoiceSpecialInfo.setPropertyCrossSign("");
                    // 40	是	货物运输特定要素-货物运输特定业务：运输工具牌号
                    // outputInvoiceIssueInvoiceSpecialInfo.setTransport_tool_num("");
                    // 20	是	出行人证件类型，
                    // 101:组织机构代码证；102:营业执照；103:税务登记证；199:其它单位证件；201:居民身份证；202:军官证；203:武警警官证；204:士兵证；205:军队离退休干部证；
                    // 206:残疾人证；207:残疾军人证（1-8级）；208:外国护照；210:港澳居民来往内地通行证；212:中华人民共和国往来港澳通行证；213:台湾居民来往大陆通行证；
                    // 214:大陆居民往来台湾通行证；215:外国人居留证；216:外交官证；217:使（领事）馆证；219:香港永久性居民身份证；218:海员证；220:台湾身份证；
                    // 221:澳门特别行政区永久性居民身份证；222:外国人身份证件；224:就业失业登记证；225:退休证；226:离休证；227:中国护照；228:城镇退役士兵自谋职业证；
                    // 229:随军家属身份证明；230:中国人民解放军军官专业证书；231:中国人民解放军义务兵退出现役证；232:中国人民解放军士官退出现役证；
                    // 233:外国人永久居留身份证（外国人永久居留证）；234:就业创业证；235:香港特别行政区护照；236:澳门特别行政区护照；237:中华人民共和国港澳居民身份证；
                    // 238:中华人民共和国台湾居民身份证；239:《中华人民共和国外国人工作许可证》（A类）；240:《中华人民共和国外国人工作许可证》（B类）；
                    // 241:《中华人民共和国外国人工作许可证》（C类）；291:医学出生证明；299:其他个人证件；
                    // outputInvoiceIssueInvoiceSpecialInfo.setCarriageId("");
                    // 	20	是	等级，仅当交通工具种类为“飞机、火车、船舶”时，必填；
                    // 	飞机：公务舱、头等舱、经济舱 火车：一等座、二等座、软席（软座、软卧）、硬席（硬座、硬卧）船舶：一等舱、二等舱、三等舱
                    // outputInvoiceIssueInvoiceSpecialInfo.setCarriageVehicleGrade("");
                    // 120	是	不动产销售服务-不动产地址，按照省、市、区/县三级传值，以&符间隔，举例“北京市&东城区、河北省&石家庄市&正定县”(不动产地址和详细地址之和为120)
                    // outputInvoiceIssueInvoiceSpecialInfo.setPropertyAddress("");
                    // 2	否	是否用于办理拖拉机和联合收割机登记 Y：是，N：否
                    // outputInvoiceIssueInvoiceSpecialInfo.setTractorRegistry("");
                    // 16	是	不动产租赁-面积单位 枚举值：平方千米、平方米、公顷、亩、h㎡、k㎡、㎡、米(乐企不支持)
                    // outputInvoiceIssueInvoiceSpecialInfo.setLeaseAreaUnit("");
                    // 20	是	出行人
                    // outputInvoiceIssueInvoiceSpecialInfo.setCarriageName("");
                    // 17	条件必填	代收车船税特定要素-车辆识别代号/车架号码，当特殊票种标志为07时必填。
                    // outputInvoiceIssueInvoiceSpecialInfo.setVehicleCode("");
                    // 120	是	不动产销售服务-详细地址，举例“北京市海淀区清华东路17号”(不动产地址和详细地址之和为120)
                    // outputInvoiceIssueInvoiceSpecialInfo.setPropertyDetailAddress("");
                    // 40	否	发动机号码
                    // outputInvoiceIssueInvoiceSpecialInfo.setTractorEngineNo("");
                    // 40	否	底盘号/机架号
                    // outputInvoiceIssueInvoiceSpecialInfo.setLeasePropertyNo("");
                    // 80	是	建筑服务特定要素-建筑项目名称
                    // outputInvoiceIssueInvoiceSpecialInfo.setBuildingName("");
                    // 13	条件必填	代收车船税特定要素-金额合计，必须大于0，当特殊票种标志为07时必填。
                    // outputInvoiceIssueInvoiceSpecialInfo.setTotalAmount(BigDecimal.valueOf(0.0));
                    // 80	是	货物运输特定要素-起运地
                    // outputInvoiceIssueInvoiceSpecialInfo.setTransport_departure("");
                    // 120	是	不动产租赁-详细地址，举例“北京市海淀区清华东路17号”（不动产地址和详细地址之和为120）
                    // outputInvoiceIssueInvoiceSpecialInfo.setLeaseDetailAddress("");
                    // 16	是	不动产销售服务-面积单位 枚举值：平方千米、平方米、公顷、亩、h㎡、k㎡、㎡
                    // outputInvoiceIssueInvoiceSpecialInfo.setPropertyAreaUnit("");
                    // 40	是	货物运输特定要素-运输工具种类，铁路运输、公路运输、水路运输、航空运输、管道运输、其他运输工具
                    // outputInvoiceIssueInvoiceSpecialInfo.setTransport_tool_type("");
                    // 8	否	二手车销售统一发票号码，特殊票种为31时该字段必填。
                    // outputInvoiceIssueInvoiceSpecialInfo.setUsedCarNo("");
                    // 12	否	二手车销售统一发票代码，特殊票种为31时该字段必填。
                    // outputInvoiceIssueInvoiceSpecialInfo.setUsedCarCode("");
                    // 20	条件必填	代收车船税特定要素-税款所属期（详细至月，格式是yyyy-MM+空格+yyyy-MM），当特殊票种标志为07时必填。
                    // outputInvoiceIssueInvoiceSpecialInfo.setTaxPeriod("");
                    // 50	否	跨区域涉税事项报验管理编号，跨地(市)标志为Y时，必填 乐企不支持
                    // outputInvoiceIssueInvoiceSpecialInfo.setKqysssxbgglBm("");
                    // 80	是	出发地 出发省市区(出发地+详细地址总长度80)
                    // outputInvoiceIssueInvoiceSpecialInfo.setCarriageLeave("");
                    // 是	交通工具类型，1：飞机；2：火车；3：长途汽车；4：公共交通；5：出租车；6：汽车；7：船舶；9：其他
                    // outputInvoiceIssueInvoiceSpecialInfo.setCarriageVehicleType("");
                    // 24,6	否	不动产销售服务-核定计税价格
                    // outputInvoiceIssueInvoiceSpecialInfo.setPropertyApprovedPrice(BigDecimal.valueOf(0.0));
                    // 13	条件必填	代收车船税特定要素-滞纳金金额，可以为0，当特殊票种标志为07时必填。
//                    outputInvoiceIssueInvoiceSpecialInfo.setLateFeeAmount(BigDecimal.valueOf(0.0));
//                    // 80	是	到达地 到达省市区(出发地+详细地址总长度80)
//                    outputInvoiceIssueInvoiceSpecialInfo.setCarriageArrive("");
//                    // 120	否	建筑服务特定要素-建筑服务详细地址，举例“北京市海淀区清华东路17号”(建筑服务发生地和详细地址之和为120)
//                    outputInvoiceIssueInvoiceSpecialInfo.setBuildingDetailAddress("");
//                    // 80	否	出发地详细地址(出发地+详细地址总长度80)
//                    outputInvoiceIssueInvoiceSpecialInfo.setCarriageLeaveAddress("");
//                    // 16	否	不动产销售服务-土地增值税项目编号
//                    outputInvoiceIssueInvoiceSpecialInfo.setPropertyLandTaxNo("");
//                    // 24,6	否	不动产销售服务-实际成交含税金额
//                    outputInvoiceIssueInvoiceSpecialInfo.setPropertyDealPrice(BigDecimal.valueOf(0.0));
//                    // 20	否	二手车销售统一发票数电票号码，特殊票种为31时该字段必填。二手车销售统一发票数电票号码、二手车销售统一发票代码和二手车销售统一发票号码需同时为空或不为空
//                    outputInvoiceIssueInvoiceSpecialInfo.setUsedCarAllelectricNo("");
//                    // 120	是	不动产租赁-不动产地址，按照省、市、区/县三级传值，以&符间隔，举例“北京市&东城区、河北省&石家庄市&正定县”（不动产地址和详细地址之和为120）
//                    outputInvoiceIssueInvoiceSpecialInfo.setLeaseAddress("");
//                    // 28	否	不动产销售服务-网签合同备案编号，不可与不动产单元代码同时填写；
//                    outputInvoiceIssueInvoiceSpecialInfo.setPropertyContractOnlineSigningNo("");
//                    // 20	是	出行人证件号码
//                    outputInvoiceIssueInvoiceSpecialInfo.setCarriageIdNo("");
//                    // 80	是	货物运输特定要素-到达地
//                    outputInvoiceIssueInvoiceSpecialInfo.setTransport_arrive("");
//                    // 8	是	不动产租赁-跨地（市）标志；标志：Y：是；N：否
//                    outputInvoiceIssueInvoiceSpecialInfo.setLeaseCrossSign("");
//                    // 16	否	建筑服务特定要素-土地增值税项目编号
//                    outputInvoiceIssueInvoiceSpecialInfo.setBuildingLandTaxNo("");
//                    // 64	否	不动产销售服务-房屋产权证书/不动产权证号码
//                    outputInvoiceIssueInvoiceSpecialInfo.setPropertyPropertyNo("");
//                    // 40	条件必填	代收车船税特定要素-牌号/船舶登记号，当特殊票种标志为07时必填。
//                    outputInvoiceIssueInvoiceSpecialInfo.setRegistrationNumber("");
//                    // 13	条件必填	代收车船税特定要素-代收车船税金额，必须大于0，当特殊票种标志为07时必填。
//                    outputInvoiceIssueInvoiceSpecialInfo.setTaxCollectedAmount(BigDecimal.valueOf(0.0));
//                    // 80	否	到达地详细地址(出发地+详细地址总长度80)
//                    outputInvoiceIssueInvoiceSpecialInfo.setCarriageArriveAddress("");
//                    // 10	是	不动产租赁-租赁期起；yyyy-MM-dd
//                    outputInvoiceIssueInvoiceSpecialInfo.setLeaseHoldDateStart("");
//                    // 80	是	货物运输特定要素-货物运输特定业务：运输货物名称
//                    outputInvoiceIssueInvoiceSpecialInfo.setTransport_goods_name("");
//                    invoiceSpecialInfoList.add(outputInvoiceIssueInvoiceSpecialInfo);
                // data.setInvoiceSpecialInfoList(invoiceSpecialInfoList);
                // 200	否	备注 乐企长度为230个字符
                data.setRemarks(invoiceForIssue.getInvoiceRemark());
            request.setData(data);
            // 64	否	组织机构编码，如果为空则上传至税号对应的机构下，如果维护了机构则按照机构归属待开信息，根据判断自行信息管理选择是否设置开票相关信息；根据组织机构编码获取销方信息
            // request.setOrgCode("");
            // 否	开具请求类型：isAsync 0 同步 1 异步 默认同步开具（仅支持rpa）
            // request.setIsAsync("0");
            //？ 30	否	开票终端代码。服务器/税务ukey 用户专普票必填，电子票非必填；税务ukey终端使用机器编号；盘用户，盘号终端选填，如果只有一个终端可不填，全电票种选填
            // request.setInvoiceTerminalCode("dzpzd008");
            // 20	是	税号
            request.setTaxNo(invoiceForIssue.getSellerNumber());
            // 否	版式生成是否推送(true / false)
            request.setFormatPushType(true);
            // 12	否	设备编号，即盘号，包括税控盘，航信盘，自持ukey。如果多个设备必填，只有一个终端可不填
            // request.setTaxDiskNo("");
            // 是否需要生成版式返回版式链接(true / false)
            request.setFormatGenerate(true);
            // 否	登录名，用于一税号多账户区分用，该登录名为税局页面登录名
            request.setTaxUserName("");

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            OutputInvoiceIssueResponse response = client.outputInvoice().issue(request, token);
            // 重载方法，可以传自定义请求唯一标识
            // OutputInvoiceIssueResponse response = client.outputInvoice().issue(request, token, requestId);
            log.info("开具接口返回：");
            log.info(JSON.toJSONString(response));
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            throw new BaseException(e.getSubMessage());
        }
    }

    /**
     * 6. 版式文件生成
     * @return
     */
    public static OutputFormatCreateResponse formatCreate(InvoiceForFormatCreate invoiceForFormatCreate)
    {
        // 获取百望token
        String token = getToken();
        try {
            OutputFormatCreateRequest request = new OutputFormatCreateRequest();
            OutputFormatCreateData data = new OutputFormatCreateData();
            data.setInvoiceNo(invoiceForFormatCreate.getInvoiceNo());
            data.setEinvoiceNo(invoiceForFormatCreate.getEinvoiceNo());
            data.setPhone(invoiceForFormatCreate.getPhone());
            data.setEmailCarbonCopy(invoiceForFormatCreate.getEmailCarbonCopy());
//            data.setInvoiceNo(invoiceForFormatCreate.getInvoiceNo());
//            data.setInvoiceCode(invoiceForFormatCreate.getInvoiceCode());
            data.setEmail(invoiceForFormatCreate.getEmail());
            data.setPushType(invoiceForFormatCreate.getPushType());
            data.setInvoiceIssueMode(invoiceForFormatCreate.getInvoiceIssueMode());
            data.setSerialNo(invoiceForFormatCreate.getSerialNo());
            request.setData(data);
            request.setTaxNo(invoiceForFormatCreate.getTaxNo());

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            OutputFormatCreateResponse response = client.outputFormat().create(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /** ======================== 销项红冲类接口 ======================== **/

    /**
     * 7. 全电红字确认单申请
     * @return
     */
    public static OutputRedinvoiceAddResponse redInvoiceAdd(InvoiceForRed invoiceForRed)
    {
        // 获取百望token
        String token = getToken();
        try {
            OutputRedinvoiceAddRequest request = new OutputRedinvoiceAddRequest();
            // 纸质、税控发票代码，【发票来源】为1时或全电纸票时必填
            // request.setOriginalPaperInvoiceCode("");
            request.setPriceTaxMark(invoiceForRed.getPriceTaxMark());
            List<OutputRedinvoiceAddObjectType> redConfirmDetailReqEntityList = new ArrayList<OutputRedinvoiceAddObjectType>();
            int goodsLineNo = 1;
            for(InvoiceEntryForRed invoiceEntryForRed : invoiceForRed.getInvoiceEntryForRedList()){
                OutputRedinvoiceAddObjectType outputRedinvoiceAddObjectType = new OutputRedinvoiceAddObjectType();

                outputRedinvoiceAddObjectType.setGoodsTaxRate(invoiceEntryForRed.getTaxRate());
                outputRedinvoiceAddObjectType.setGoodsTotalPriceTax(invoiceEntryForRed.getAmount().multiply(new BigDecimal(-1)).setScale(2, RoundingMode.HALF_UP));
                // 商品服务简称(税收分类简称)
                // outputRedinvoiceAddObjectType.setGoodsSimpleName("\u8C37\u7269");
                outputRedinvoiceAddObjectType.setGoodsTotalPrice(invoiceEntryForRed.getAmount().multiply(new BigDecimal(-1)).setScale(2, RoundingMode.HALF_UP));
                // 含税单价，当含税标志为1-含税时，如需要，传此值
                // outputRedinvoiceAddObjectType.setGoodsPriceTax(invoiceEntryForRed.getPrice().setScale(2, RoundingMode.HALF_UP));
                // 蓝字发票明细序号
                outputRedinvoiceAddObjectType.setOriginalInvoiceDetailNo(invoiceEntryForRed.getGoodsLineNo());
                // 规格型号，也可代表车架号/车辆识别号
                outputRedinvoiceAddObjectType.setGoodsSpecification(invoiceEntryForRed.getSpecificatCode());
                // 不含税单价，当含税标志为0-不含税时，如需要，传此值
                // outputRedinvoiceAddObjectType.setGoodsPrice(invoiceEntryForRed.getPrice()+"");
                // 数量
                outputRedinvoiceAddObjectType.setGoodsQuantity(invoiceEntryForRed.getQty().multiply(new BigDecimal(-1)).setScale(2, RoundingMode.HALF_UP).toString());
                // 单位
                outputRedinvoiceAddObjectType.setGoodsUnit(invoiceEntryForRed.getUnit());
                // 税额
                outputRedinvoiceAddObjectType.setGoodsTotalTax(invoiceEntryForRed.getTax().multiply(new BigDecimal(-1)).setScale(2, RoundingMode.HALF_UP));
                // 税收分类编码(商品和服务税收分类合并编码)
                outputRedinvoiceAddObjectType.setGoodsCode(invoiceEntryForRed.getProductCode());
                // 项目名称(自定义商品名称)
                outputRedinvoiceAddObjectType.setProjectName(invoiceEntryForRed.getProductName());
                // 商品全称（ 简称自定义名称）
                outputRedinvoiceAddObjectType.setGoodsName(invoiceEntryForRed.getProductName());
                // 序号
                outputRedinvoiceAddObjectType.setGoodsLineNo(goodsLineNo++);
                redConfirmDetailReqEntityList.add(outputRedinvoiceAddObjectType);
            }

            request.setRedConfirmDetailReqEntityList(redConfirmDetailReqEntityList);
            // 纸质、税控发票号码，【发票来源】为1时或全电纸票时必填
            // request.setOriginalPaperInvoiceNo("");
            // 红票客户邮箱
            // request.setBuyerEmail("");
            // 非确认即开—自动开票； Y：自动开票； N：不自动开票，默认为N；
            // 红字确认单需确认时，对方确认完成，百望系统将自动开红票，WEB连接器和乐企均支持；
            // 乐企自动开票为Y时，默认开票人（云开票配置处配置）不能为空，否则无法自动开票；场景说明：当税局“确认即开票“标识为”否“时，可通过传入此字段确定是否自动开票。
            request.setAutoIssueSwitch("Y");
            // 红字冲销税额
            request.setInvoiceTotalTax(invoiceForRed.getRedTotalTax().multiply(new BigDecimal(-1)).setScale(2, RoundingMode.HALF_UP));
            // 是否纸质发票标志 Y：纸质发票 N：电子发票
            request.setOriginInvoiceIsPaper("N");
            // 红字发票冲红原因代码 01:开票有误 02:销货退回 03:服务中止 04:销售折让。二手车销售统一发票仅可使用01、02
            request.setRedInvoiceLabel(invoiceForRed.getRedReason());
            // 蓝字发票合计税额
            request.setOriginInvoiceTotalTax(invoiceForRed.getInvoiceTotalTax());
            // 蓝字发票特定要素类型代码 01：成品油发票 02：稀土发票 03：建筑服务发票 04：货物运输服务发票 05：不动产销售服务发票 06：不动产租赁服务发票 07：代收车船税 08：通行费 09：旅客运输服务发票 10：医疗服务（住院）发票 11：医疗服务（门诊）发票 12：自产农产品销售发票 13 拖拉机和联合收割机发票 14：机动车 15：二手车 16：农产品收购发票 17：光伏收购发票 18：卷烟发票 31：二手车* 24：报废产品收购；32：电子烟
            // request.setOriginInvoiceSetCode("");
            // request.setOrgCode("");
            // 销售方名称
            request.setSellerTaxName(invoiceForRed.getSellerName());
            // 1：使用蓝票邮箱、手机号交付；0：使用入参中的buyerEmail、buyerPhone交付，buyerEmail、buyerPhone为空则不交付；
            request.setDeliverFlag("1");
            // 机构税号
            request.setTaxNo(invoiceForRed.getSellerNumber());
            // 蓝字发票开票日期 yyyy-MM-dd HH:mm:ss
            request.setOriginInvoiceDate(invoiceForRed.getInvoiceDate());
            // 数电票票种（仅支持WEB连接器），N电子发票，Y纸质发票 ，默认N，只有原蓝票为纸质发票时，此字段生效；机动车统一销售发票、二手车统一销售发票，默认Y，目前不支持N；
            //request.setRedInvoiceIsPaper("");
            // 购买方统一社会信用代码/纳税人识别号/身份证件号码, 录入方身份为【购方】时必填
            // request.setBuyerTaxNo("");
            // 录入方身份 01:销方,02:购方,03:二手车市场/拍卖企业
            request.setEntryIdentity("01");
            // request.setDrawer("");
            // 蓝字发票全电发票号码，【发票来源】为2时必填
            request.setOriginalInvoiceNo(invoiceForRed.getInvoiceNo());
            // 发票来源：全电平台红冲必须要传递的字段
            // 1:增值税发票管理系统：表示此发票是通过原税控系统开具的增值税发票，红冲此类发票时，税控设备需注销后才可以申请全电的红字确认单；
            // 2:电子发票服务平台：表示此发票是通过电子发票服务平台开具的全电发票（包括全电纸质发票），红冲此类发票时需要传递蓝票属性为此；
            request.setInvoiceSource("2");
            // 蓝字发票合计金额
            request.setOriginInvoiceTotalPrice(invoiceForRed.getInvoiceTotalPrice());
            // 销售方统一社会信用代码/纳税人识别号/身份证件号码
            request.setSellerTaxNo(invoiceForRed.getSellerNumber());
            //
            request.setBuyerPhone(invoiceForRed.getBuyerTel());
            // 蓝字发票票种代码 01:增值税专用发票 02:普通发票 03:机动车统一销售发票 04:二手车统一销售发票
            request.setOriginInvoiceType(invoiceForRed.getInvoiceType());
            // 	红字冲销金额
            request.setInvoiceTotalPrice(invoiceForRed.getRedTotalPrice().multiply(new BigDecimal(-1)).setScale(2, RoundingMode.HALF_UP));
            // 购买方名称
            request.setBuyerTaxName(invoiceForRed.getBuyerName());
            // request.setTaxUserName("");
            request.setRedConfirmSerialNo("HC" + invoiceForRed.getApplyNo());

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            OutputRedinvoiceAddResponse response = client.outputRedinvoice().add(request, token);
            // 重载方法，可以传自定义请求唯一标识
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /**
     * 8. 红字确认单操作
     * @return
     */
    public static boolean redInvoiceOperate()
    {
        // 获取百望token
        String token = getToken();
        try {
            OutputRedinvoiceOperateRequest request = new OutputRedinvoiceOperateRequest();
            request.setRedConfirmUuid("6df741db489945bcae761d0338087435");
            request.setSellerTaxNo("91440604570155821Y");
            request.setRedConfirmNo("44060422121001100222");
            request.setTaxNo("91440604570155821Y");
            request.setConfirmType("01");
            request.setTaxUserName("");

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            OutputRedinvoiceOperateResponse response = client.outputRedinvoice().operate(request, token);
            // 重载方法，可以传自定义请求唯一标识
            // OutputRedinvoiceOperateResponse response = client.outputRedinvoice().operate(request, token, requestId);
            System.out.println(response);

        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
        return false;
    }

    /**
     * 9. 使用红字确认单开具负数发票
     * @return
     */
    public static boolean redInvoiceIssued()
    {
        // 获取百望token
        String token = getToken();
        try {
            OutputRedinvoiceIssuedRequest request = new OutputRedinvoiceIssuedRequest();
            request.setRedConfirmUuid("");
            request.setSellerTaxNo("");
            request.setDrawer("");
            request.setTaxNo("");
            request.setSerialNo("");
            request.setTaxUserName("");
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            OutputRedinvoiceIssuedResponse response = client.outputRedinvoice().issued(request, token);
            // 重载方法，可以传自定义请求唯一标识
            // OutputRedinvoiceIssuedResponse response = client.outputRedinvoice().issued(request, token, requestId);
            System.out.println(response);

        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
        return false;
    }

    /** ======================== 进项发票采集类接口 ======================== **/

    /**
     * 10. ORC识别（自动查验）
     * @return
     */
    public static ImageInvoicesRecogcollectResponse recogcollect(List<InvoiceForRecogcollect> invoiceForRecogcollectList)
    {
        // 获取百望token
        String token = getToken();
        try {
            ImageInvoicesRecogcollectRequest request = new ImageInvoicesRecogcollectRequest();
            // ist<ImageInvoicesRecogcollectFileBase64Info>, 图片或源文件的base64及文件名的集合
            List<ImageInvoicesRecogcollectFileBase64Info> filesMap = new ArrayList<ImageInvoicesRecogcollectFileBase64Info>();

            for(InvoiceForRecogcollect invoiceForRecogcollect : invoiceForRecogcollectList) {
                ImageInvoicesRecogcollectFileBase64Info imageInvoicesRecogcollectFileBase64Info = new ImageInvoicesRecogcollectFileBase64Info();
                // 文件名称(带后缀名)
                imageInvoicesRecogcollectFileBase64Info.setFileName(invoiceForRecogcollect.getFileName());
                // 文件Base64
                imageInvoicesRecogcollectFileBase64Info.setFileBase64(invoiceForRecogcollect.getFileBase64());
                filesMap.add(imageInvoicesRecogcollectFileBase64Info);
            }
            request.setFilesMap(filesMap);
            // 采集来源，1：客户端，2：网页，3：移动端-app，4：接口，5：移动端-H5，6：企业邮箱，7：个人邮箱,9：自定义,99：其他
            request.setCollectWay(0);
            // 1	否	发票签收状态【默认0】(0-未签收,1-已签收）
            request.setSignStatus(1);
            // 20	是	用户账号
            request.setUserAccount(username);
            // 	30	否	业务系统代码。当web页面-基础应用设置中的“采集必填业务系统”开关开启后，此字段必填
            request.setCollectInvUseType("");
            // 20	否	票夹id
            request.setFolderId("");
            // 	1	否	是否入库（0：入库，1：不入库。不填时默认为0）
            request.setIsSave(0);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ImageInvoicesRecogcollectResponse response = client.imageInvoices().recogcollect(request, token);
            // 重载方法，可以传自定义请求唯一标识
            // ImageInvoicesRecogcollectResponse response = client.imageInvoices().recogcollect(request, token, requestId);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 11. 采集新增
     * @return
     */
    public static ImageInvoicesInvoicemanageaddResponse invoicemanageadd(List<InvoiceForinvoicemanageadd> invoiceForinvoicemanageaddList)
    {
        // 获取百望token
        String token = getToken();
        try {
            ImageInvoicesInvoicemanageaddRequest request = new ImageInvoicesInvoicemanageaddRequest();
            // 采集方式 1：客户端，2：网页，3：移动端-app，4：接口，5：移动端-H5，6：企业邮箱，7：个人邮箱,9：自定义,99：其他
            request.setCollectWay(0);
            // 发票归属机构代码
            request.setOrgCode("");
            // 用户账号
            request.setUserAccount(username);
            // 添加文件合集
            List<ImageInvoicesInvoicemanageaddMediaFileBase64IspInfo> mediaFileBase64IspInfoList = new ArrayList<ImageInvoicesInvoicemanageaddMediaFileBase64IspInfo>();
            //
            ImageInvoicesInvoicemanageaddMediaFileBase64IspInfo imageInvoicesInvoicemanageaddMediaFileBase64IspInfo = new ImageInvoicesInvoicemanageaddMediaFileBase64IspInfo();
            // 不加附件
//            imageInvoicesInvoicemanageaddMediaFileBase64IspInfo.setFileName("1.jpg");
//            imageInvoicesInvoicemanageaddMediaFileBase64IspInfo.setFileBase64("/9j/4AAQSkZJ");
            // 添加发票合集
            List<ImageInvoicesInvoicemanageaddMediaInvoiceIspInfo> mediaInvoiceIspInfoList = new ArrayList<ImageInvoicesInvoicemanageaddMediaInvoiceIspInfo>();
            for(InvoiceForinvoicemanageadd invoiceForinvoicemanageadd : invoiceForinvoicemanageaddList){
                ImageInvoicesInvoicemanageaddMediaInvoiceIspInfo imageInvoicesInvoicemanageaddMediaInvoiceIspInfo = new ImageInvoicesInvoicemanageaddMediaInvoiceIspInfo();
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setHasTraveller(invoiceForinvoicemanageadd.getHasTraveller());
                Map<String, Object> ext = new HashMap<String, Object>();
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setExt(ext);
                // 火车票序列号
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setSerialNum(invoiceForinvoicemanageadd.getSerialNum());
                // 全电发票号码
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setElectronicNo(invoiceForinvoicemanageadd.getElectronicNo());
                // 发票签收状态
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setSignStatus(Integer.parseInt(invoiceForinvoicemanageadd.getSignStatus()));
                // 乘车人，当上传航空电子客票行程单、航空电子客票行程单退票费时，此字段必填；
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setDrawer(invoiceForinvoicemanageadd.getDrawer());
                // 发票附件合集
                List<ImageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo> mediaAttFileBase64IspInfoList = new ArrayList<ImageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo>();
//                ImageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo imageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo = new ImageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo();
//                imageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo.setAttFileBase64("/9j/4AA");
//                imageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo.setAttFileName("1111.jpg");
//                mediaAttFileBase64IspInfoList.add(imageInvoicesInvoicemanageaddMediaAttFileBase64IspInfo);

                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setMediaAttFileBase64IspInfoList(mediaAttFileBase64IspInfoList);
                // 开票日期：YYYY-MM-DD
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setInvoiceDate(invoiceForinvoicemanageadd.getInvoiceDate());
                // 主管税务机关名称
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setTaxAuthoritiesName(invoiceForinvoicemanageadd.getTaxAuthoritiesName());
                // 发票代码
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setInvoiceCode(invoiceForinvoicemanageadd.getInvoiceCode());
                // 校验码
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setCheckCode(invoiceForinvoicemanageadd.getCheckCode());
                // 合计税额，飞机燃油附加费	BigDecimal	20,2	合计税额，1003-航空电子客票行程单：燃油附加费；1016-航空电子客票行程单退票费：燃油附加费；
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setTotalTax(invoiceForinvoicemanageadd.getTotalTax() == null ? BigDecimal.valueOf(0.0) : invoiceForinvoicemanageadd.getTotalTax());
                // 民航发展基金
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setCivilAviationFund(invoiceForinvoicemanageadd.getCivilAviationFund() == null ? BigDecimal.valueOf(0.0) : invoiceForinvoicemanageadd.getCivilAviationFund());
                // 合计金额,火车票金额，飞机票价
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setTotalAmount(invoiceForinvoicemanageadd.getTotalAmount() == null ? BigDecimal.valueOf(0.0) : invoiceForinvoicemanageadd.getTotalAmount());
                // 燃油附加费	BigDecimal	20,2	燃油附加费，1003-航空电子客票行程单、61-数电票（航空运输电子客票行程单）、1016-航空电子客票行程单退票费返回；
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setOilSurcharge(invoiceForinvoicemanageadd.getOilSurcharge() == null ? BigDecimal.valueOf(0.0) : invoiceForinvoicemanageadd.getOilSurcharge());
                // 国内国际标识
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setDomesticOrInternational(invoiceForinvoicemanageadd.getDomesticOrInternational());
                //发票类型
                // 99 其他发票 01 增值税专用发票 03 机动车销售统一发票 04 增值税普通发票 08 增值税电子专用发票 10 增值税电子普通发票
                // 11 增值税普通发票(卷式) 14 增值税电子普通发票(通行费) 15 二手车销售统一发票 31 数电发票（增值税专用发票）
                // 32 数电发票（增值税普通发票） 1002 火车票 1003 航空电子客票行程单 1004 出租车发票 1005 通用定额发票
                // 1006 公路水路客运发票 1007 通用机打发票 1008 过路费发票 1009 区块链电子发票 1010 火车票退票费 1011 医疗电子票据（住院）
                // 1012 医疗电子票据（门诊） 1013 通用（电子）发票 51 数电发票（铁路电子客票） 61 数电发票（航空运输电子客票行程单）
                // 83 电子发票（机动车销售统一发票） 84 电子发票（二手车销售统一发票） 85 数电纸质发票（增值税专用发票） 86 数电纸质发票（增值税普通发票）
                // 1015 海关缴款书 1016 航空运输电子客票行程单退改费
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setInvoiceType(invoiceForinvoicemanageadd.getInvoiceType());
                // 业务系统配置 系统配置后必填
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setCollectInvUseType("");
                // 车次号或航班号 当发票为火车票时该参数为必填
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setTrainNumber(invoiceForinvoicemanageadd.getTrainNumber());
                // 发票号码；51-数电票（铁路电子客票）、61-数电票（航空运输电子客票行程单）上传时非必填，其他票种必填；1003-航空运输电子客票行程单电子客票号、1016-航空运输电子客票行程单退票费的电子客票号；
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setInvoiceNo(invoiceForinvoicemanageadd.getInvoiceNo());
                // 价税合计，飞机合计金额，火车等总金额 当上传航空电子客票行程单、航空电子客票行程单退票费时，此字段必填；
                imageInvoicesInvoicemanageaddMediaInvoiceIspInfo.setAmountTax(invoiceForinvoicemanageadd.getAmountTax() == null ? BigDecimal.valueOf(0.0) : invoiceForinvoicemanageadd.getAmountTax());
                mediaInvoiceIspInfoList.add(imageInvoicesInvoicemanageaddMediaInvoiceIspInfo);
            }

            imageInvoicesInvoicemanageaddMediaFileBase64IspInfo.setMediaInvoiceIspInfoList(mediaInvoiceIspInfoList);
            mediaFileBase64IspInfoList.add(imageInvoicesInvoicemanageaddMediaFileBase64IspInfo);
            request.setMediaFileBase64IspInfoList(mediaFileBase64IspInfoList);
            // 是否入库（0：入库 ，1：不入库。不填默认为0）
            request.setIsSave(0);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ImageInvoicesInvoicemanageaddResponse response = client.imageInvoices().invoicemanageadd(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 12. 查询发票的真伪，并获取发票的全票面信息
     *  == 1.发票查验InputComplianceValidate (2)
     * @return
     */
    public static InputComplianceValidateResponse validate(InvoiceForValidate invoiceForValidate)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputComplianceValidateRequest request = new InputComplianceValidateRequest();
            request.setBillingDate(invoiceForValidate.getBillingDate());
            request.setTotalAmount(invoiceForValidate.getTotalAmount());
            request.setInvoiceNumber(invoiceForValidate.getInvoiceNumber());
            // 校验码后6位 说明：
            // 1.发票类型为04-增值税普通发票、10-增值税电子普通发票、11-增值税普通发票(卷式)、14-道路通行费电子普通发票、86-数电纸质发票（普通发票）时必填;
            // 2.发票类型为86-数电纸质发票（普通发票）时填写20位数
            //电票号码的后6位；
            request.setCheckCode_6(invoiceForValidate.getCheckCode());
            request.setInvoiceType(invoiceForValidate.getInvoiceType());
            request.setTaxNo(invoiceForValidate.getTaxNo());
            request.setInvoiceCode(invoiceForValidate.getInvoiceCode());
            request.setElectricType(invoiceForValidate.getElectricType());

            IBWClient client = new BWRestClient(url, appKey, appSecret); // 初始化一个客户端
            InputComplianceValidateResponse response = client.inputCompliance().validate(request, token);
            // 重载方法，可以传自定义请求唯一标识
            // InputComplianceValidateResponse response = client.inputCompliance().validate(request, token, requestId);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /** ======================== 进项发票同步类接口 ======================== **/

    /**
     * 13. 获取本税号下国税选择确认平台（包括未抵扣和已抵扣）的抵扣类发票信息。
     * @return
     */
    public static InputInvoicedataSyncResponse invoiceDeductionDataSync(String taxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputInvoicedataSyncRequest request = new InputInvoicedataSyncRequest();
            request.setTaxNo(taxNo);
            IBWClient client = new BWRestClient(url, appKey, appSecret); // 初始化一个客户端
            InputInvoicedataSyncResponse response = client.inputInvoicedata().sync(request, token);
            System.out.println(response);
            // 重载方法，可以传自定义请求唯一标识
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 14. 当调用接口（baiwang.input.invoicedata.sync）成功获取第一页1000条发票数据后，可调用本接口
     * 反馈结果成功后，下次再次调用接口（baiwang.input.invoicedata.sync）将会取到下一页1000条发
     * 票数据。
     * @return
     */
    public static InputInvoicedataSyncresultResponse invoicedataSyncresult( String taskNo, String taxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputInvoicedataSyncresultRequest request = new InputInvoicedataSyncresultRequest();
            request.setTaskNo(taskNo);
            request.setTaxNo(taxNo);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputInvoicedataSyncresultResponse response = client.inputInvoicedata().syncresult(request, token);
            System.out.println(response);
            // 重载方法，可以传自定义请求唯一标识
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 15. 持按时间段查询本税号下进销项发票数据的页码列表，查询成功后，可使用页码调用接口
     * baiwang.channel.invoicedata.getpagedata来获取每个页码的发票数据。相同的税号、时间段、业
     * 务类型（进销项）每天仅有3次下载机会
     * @param  taxNo 税号
     * @param  dateType month-按月 day-按
     * @param  invoiceDate 日期类型为month：格式为：YYYYMM；日期类型为day格式为：YYYYMM
     * @param  businessType output_vat：销项 input_vat 进项
     * @return
     */
    public static ChannelInvoicedataGetpagenoResponse getpageno(String taxNo, String dateType, String invoiceDate, String businessType)
    {
        // 获取百望token
        String token = getToken();
        try {
            ChannelInvoicedataGetpagenoRequest request = new ChannelInvoicedataGetpagenoRequest();
            request.setTaxNo(taxNo);
            request.setDateType(dateType);
            request.setInvoiceDate(invoiceDate);
            request.setBusinessType(businessType);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ChannelInvoicedataGetpagenoResponse response = client.channelInvoicedata().getpageno(request, token);
            System.out.println(response);
            // 重载方法，可以传自定义请求唯一标识
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 16. 获取15中的详细发票信息
     * @param  taxNo 税号
     * @param  invoiceDate 日期类型为month：格式为：YYYYMM；日期类型为day格式为：YYYYMM
     * @param  businessType output_vat：销项 input_vat 进项
     * @param  pageNo 页码号
     * @return
     */
    public static ChannelInvoicedataGetpagedataResponse getpagedata(String taxNo, String invoiceDate, String businessType, Long pageNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            ChannelInvoicedataGetpagedataRequest request = new ChannelInvoicedataGetpagedataRequest();
            request.setTaxNo(taxNo);
            request.setPageNo(pageNo);
            request.setInvoiceDate(invoiceDate);
            request.setBusinessType(businessType);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            ChannelInvoicedataGetpagedataResponse response = client.channelInvoicedata().getpagedata(request, token);
            System.out.println(response);
            // 重载方法，可以传自定义请求唯一标识
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /** ======================== 抵扣类接口 ======================== **/
    /**
     * 17. 勾选抵扣申请
     * @param  taxNo 税号
     * @param  period 税款所属期 201811
     * @param  deductionApplyInvoiceList 抵扣发票集合
     * @return
     */
    public static InputDeductionApplyResponse deductionApply(String taxNo, String period, List<DeductionApplyInvoice> deductionApplyInvoiceList)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionApplyRequest request = new InputDeductionApplyRequest();
            // 税款所属期
            request.setPeriod(period);
            // 税号
            request.setTaxNo(taxNo);

            List<InputDeductionApplyInvoice> invoiceList = new ArrayList<InputDeductionApplyInvoice>();
            for(DeductionApplyInvoice deductionApplyInvoice : deductionApplyInvoiceList){
                InputDeductionApplyInvoice inputDeductionApplyInvoice = new InputDeductionApplyInvoice();
                BeanUtils.copyProperties(deductionApplyInvoice, inputDeductionApplyInvoice);
                invoiceList.add(inputDeductionApplyInvoice);
            }

            request.setInvoiceList(invoiceList);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionApplyResponse response = client.inputDeduction().apply(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 18. 勾选抵扣申请结果查询
     * @param  taxNo 税号
     * @param  invoiceCode 发票代码位数为10位或12位 非必填
     * @param  invoiceNumber 发票号码
     * @param  eInvoiceNumber 数电发票号码 非必填
     * @param  taskNo 任务号(勾选抵扣申请任务返回的
     * @return
     */
    public static InputDeductionApplyresultResponse deductionApplyResult(String taxNo, String invoiceCode, String invoiceNumber, String eInvoiceNumber, String taskNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionApplyresultRequest request = new InputDeductionApplyresultRequest();
            // 税号
            request.setTaxNo(taxNo);
            // 发票号码
            request.setInvoiceNumber(invoiceNumber);
            // 任务号
            request.setTaskNo(taskNo);
            // 数电发票号码
            request.setEInvoiceNumber(eInvoiceNumber);
            // 发票代码位数为10位或12位
            request.setInvoiceCode(invoiceCode);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionApplyresultResponse response = client.inputDeduction().applyresult(request,token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /**
     * 19. 3.取消勾选抵扣申请InputDeductionCancel
     * 将“已抵扣”的专票类发票取消抵扣，当前税期统计表状态为“未生成”才能调用成功。一般用于
     * 抵扣错误或调整抵扣税额的情况下使用。
     * @param  taxNo 税号
     * @param  period 税款所属期
     * @param  deductionApplyInvoiceList 抵扣发票集合
     * @return
     */
    public static InputDeductionCancelResponse deductionCancel(String taxNo, String period, List<DeductionApplyInvoice> deductionApplyInvoiceList)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionCancelRequest request = new InputDeductionCancelRequest();
            // 税款所属期
            request.setPeriod(period);
            // 税号
            request.setTaxNo(taxNo);

            List<InputDeductionCancelCancelDeductibleRequsetInvoice> invoiceList = new ArrayList<InputDeductionCancelCancelDeductibleRequsetInvoice>();
            for(DeductionApplyInvoice deductionApplyInvoice : deductionApplyInvoiceList){
                InputDeductionCancelCancelDeductibleRequsetInvoice inputDeductionCancelCancelDeductibleRequsetInvoice = new InputDeductionCancelCancelDeductibleRequsetInvoice();
                BeanUtils.copyProperties(deductionApplyInvoice, inputDeductionCancelCancelDeductibleRequsetInvoice);
                invoiceList.add(inputDeductionCancelCancelDeductibleRequsetInvoice);
            }
            request.setInvoiceList(invoiceList);
            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionCancelResponse response = client.inputDeduction().cancel(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 20. 4.取消勾选抵扣申请结果获取 InputDeductionCancelresult
     * @param  taxNo 购方税号
     * @param  invoiceCode 发票代码 非必填
     * @param  invoiceNumber 发票号码
     * @return
     */
    public static InputDeductionCancelresultResponse deductionCancelResult(String taxNo, String invoiceCode, String invoiceNumber)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionCancelresultRequest request = new InputDeductionCancelresultRequest();
            // 税号
            request.setTaxNo(taxNo);
            // 发票代码
            request.setInvoiceCode(invoiceCode);
            // 发票号码
            request.setInvoiceNumber(invoiceNumber);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionCancelresultResponse response = client.inputDeduction().cancelresult(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 21. 勾选不抵扣申请
     * @param  taxNo 税号
     * @param  period 税款所属期
     * @param  deductionApplyorCancelnonList 不抵扣发票集合
     * @return
     */
    public static InputDeductionApplyorcancelnonResponse deductionApplyorCancelnon(String taxNo, String period, List<DeductionApplyorCancelnon> deductionApplyorCancelnonList)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionApplyorcancelnonRequest request = new InputDeductionApplyorcancelnonRequest();
            // 税款所属期
            request.setPeriod(period);
            // 税号
            request.setTaxNo(taxNo);

            List<InputDeductionApplyorcancelnonNoDeductionRequestInvoice> invoiceList = new ArrayList<InputDeductionApplyorcancelnonNoDeductionRequestInvoice>();
            for(DeductionApplyorCancelnon deductionApplyorCancelnon : deductionApplyorCancelnonList){
                InputDeductionApplyorcancelnonNoDeductionRequestInvoice inputDeductionApplyorcancelnonNoDeductionRequestInvoice = new InputDeductionApplyorcancelnonNoDeductionRequestInvoice();
                BeanUtils.copyProperties(deductionApplyorCancelnon, inputDeductionApplyorcancelnonNoDeductionRequestInvoice);
                invoiceList.add(inputDeductionApplyorcancelnonNoDeductionRequestInvoice);
            }
            request.setInvoiceList(invoiceList);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionApplyorcancelnonResponse response = client.inputDeduction().applyorcancelnon(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }

        }
    }

    /**
     * 22. 勾选不抵扣申请结果查询
     * @param  taxNo 税号
     * @param  invoiceCode 发票代码位数为10位或12位 非必填
     * @param  invoiceNumber 发票号码
     * @param  certificationType 不抵扣类型 4-确认不抵扣，6-取消不抵扣
     * @param  eInvoiceNumber 数电发票号码 非必填
     * @param  taskNo 任务号(勾选抵扣申请任务返回的
     * @return
     */
    public static InputDeductionApplyorcancelnonresultResponse deductionApplyorCancelnonResult(String taxNo, String invoiceCode, String invoiceNumber, String certificationType, String eInvoiceNumber, String taskNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionApplyorcancelnonresultRequest request = new InputDeductionApplyorcancelnonresultRequest();
            // 税号
            request.setTaxNo(taxNo);
            // 发票号码
            request.setInvoiceNumber(invoiceNumber);
            // 任务号
            request.setTaskNo(taskNo);
            // 数电发票号码
            request.setEInvoiceNumber(eInvoiceNumber);
            // 发票代码位数为10位或12位
            request.setInvoiceCode(invoiceCode);
            // 不抵扣类型 4-确认不抵扣，6-取消不抵扣
            request.setCertificationType(certificationType);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionApplyorcancelnonresultResponse response = client.inputDeduction().applyorcancelnonresult(request,token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }


    /** ======================== 统计表类接口 ======================== **/

    /**
     * 23. 5.统计表生成&撤销申请InputDeductionStatapply
     * @param  period 税款所属期
     * @param  taskType 统计表操作类型 1-统计表申请 2-统计表撤销
     * @param  buyerTaxNo 购方税号
     * @return
     */
    public static InputDeductionStatapplyResponse deductionStatApply(String period, String taskType, String buyerTaxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionStatapplyRequest request = new InputDeductionStatapplyRequest();
            // 税款所属期 格式：yyyyMM
            request.setPeriod(period);
            // 统计表操作类型 1-统计表申请 2-统计表撤销
            request.setTaskType(taskType);
            // 购方税号
            request.setBuyerTaxNo(buyerTaxNo);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionStatapplyResponse response = client.inputDeduction().statapply(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /**
     * 24. 6.统计表生成&撤销申请结果获取InputDeductionStatapplyresult
     * @param  period 税款所属期
     * @param  taskType 统计表操作类型 1-统计表申请 2-统计表撤销
     * @param  buyerTaxNo 购方税号
     * @return
     */
    public static InputDeductionStatapplyresultResponse deductionStatApplyResult(String period, String taskType, String buyerTaxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionStatapplyresultRequest request = new InputDeductionStatapplyresultRequest();
            // 税款所属期 格式：yyyyMM
            request.setPeriod(period);
            // 统计表操作类型 1-统计表申请 2-统计表撤销
            request.setTaskType(taskType);
            // 购方税号
            request.setBuyerTaxNo(buyerTaxNo);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionStatapplyresultResponse response = client.inputDeduction().statapplyresult(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }


    /**
     * 25. 确认&取消确定统计表申请
     * @param  period 税款所属期
     * @param  taskType 任务类型  1-确认签名申请 2-取消签名
     * @param  buyerTaxNo 购方税号
     * @return
     */
    public static InputDeductionStatconfirmorcancelResponse deductionStatconfirmOrCancel(String period, String taskType, String buyerTaxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionStatconfirmorcancelRequest request = new  InputDeductionStatconfirmorcancelRequest();
            // 税款所属期 格式：yyyyMM
            request.setPeriod(period);
            // 统计表操作类型 1-统计表申请 2-统计表撤销
            request.setTaskType(taskType);
            // 购方税号
            request.setBuyerTaxNo(buyerTaxNo);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionStatconfirmorcancelResponse response = client.inputDeduction().statconfirmorcancel(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /**
     * 26. 确认&取消确定统计表申请InputDeductionStatconfirmorcancelresult
     * @param  period 税款所属期
     * @param  taskType 统计表操作类型 1-统计表申请 2-统计表撤销
     * @param  buyerTaxNo 购方税号
     * @return
     */
    public static InputDeductionStatconfirmorcancelresultResponse deductionStatconfirmorcancelResult(String period, String taskType, String buyerTaxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionStatconfirmorcancelresultRequest request = new InputDeductionStatconfirmorcancelresultRequest();
            // 税款所属期 格式：yyyyMM
            request.setPeriod(period);
            // 统计表操作类型 1-统计表申请 2-统计表撤销
            request.setTaskType(taskType);
            // 购方税号
            request.setBuyerTaxNo(buyerTaxNo);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionStatconfirmorcancelresultResponse response = client.inputDeduction().statconfirmorcancelresult(request, token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }

    /**
     * 27. 查看对应税号下某个税期的统计表状态，如果统计表已生成，则将同时返回统计表的详情。
     * @param  period 税款所属期
     * @param  buyerTaxNo 购方税号
     * @return
     */
    public static InputDeductionGetstatistatusResponse deductionGetstatis(String period, String buyerTaxNo)
    {
        // 获取百望token
        String token = getToken();
        try {
            InputDeductionGetstatistatusRequest request = new InputDeductionGetstatistatusRequest();
            // 税期
            request.setPeriod(period);
            // 购方税号
            request.setBuyerTaxNo(buyerTaxNo);

            // 初始化一个客户端
            IBWClient client = new BWRestClient(url, appKey, appSecret);
            InputDeductionGetstatistatusResponse response = client.inputDeduction().getstatistatus(request,token);
            System.out.println(response);
            return response;
        } catch (BWOpenException e) {
            e.printStackTrace();
            log.info(e.getCode());
            log.info(e.getMessage());
            log.info(e.getSubCode());
            log.info(e.getSubMessage());
            if(e.getSubMessage().split(", msg:").length > 1){
                throw new BaseException(e.getSubMessage().split(", msg:")[1]);
            } else {
                throw new BaseException(e.getSubMessage());
            }
        }
    }


    /**
     * 99. 查询数电发票
     */
    public static OutputEinvoiceQueryResponse queryInvoiceByInvoiceNo(String taxNo, String invoiceNo){
        String token = BaiwangUtils.getToken();
        OutputEinvoiceQueryRequest request = new OutputEinvoiceQueryRequest();
        OutputEinvoiceQueryInvoiceQueryParam data = new OutputEinvoiceQueryInvoiceQueryParam();
        data.setInvoiceNo(invoiceNo);
//        data.setExpressNo("");
//        data.setContractNo("");
//        data.setPageSize(1);
//        data.setQueryAll(false);
//        // 征税方式， 0：普通征税；2：差额征税（默认是0普通征税）
//        data.setTaxationMethod("");
//        data.setSystemName("");
//        data.setInvoiceCheckMark("");
//        data.setPageNo(1);
//        // 开票终端代码。服务器/税务ukey 用户专普票必填，电子票非必填；税务ukey终端使用机器编号；盘用户，盘号终端选填，如果只有一个终端可不填，全电票种选填
//        data.setInvoiceTerminalCode("");
//        // 开票类型 0:正数发票（蓝票） 1：负数发票（红票）默认0
//        data.setInvoiceType("");
//        //
//        data.setMachineNo("");
//
//        data.setInvoiceEndDate("");
//        Map<String, Object> ext = new HashMap<String, Object>();
//        data.setExt(ext);
//        data.setSystemId("");
//        // 发票请求流水号
//        data.setOrderNo("");
//        // 购方单位税号， invoiceTypeCode=004、028、01（增值税专用发票、增值税电子专用发票、全电发票（增值税专用发票））开具时必传 invoiceSpecialMark=16|17（农产品收购、光伏收购）开具时必传
//        data.setBuyerTaxNo("");
//        data.setPrintStatus("");
//        // 特殊票种标志， 00：普通发票；01：农产品销售；02：农产品收购；08：成品油 机动车（默认是00普通发票）;16矿产品；03稀土；
//        // 全电类发票特殊票种标志：01 成品油发票；03：建筑服务发票；04：货物运输服务发票；05：不动产销售服务发票；06：不动产租赁服务发票；09：旅客运输发票；12：自产农产品销售；13：拖拉机和联合收割机；14：机动车；15：二手车；16：农产品收购；31：二手车*；24：报废产品收购；02：稀土；17：光伏收购；07：代收车船税；32：电子烟；18卷烟
//        data.setInvoiceSpecialMark("");
//        // 购方单位名称 全电为100个字符
//        data.setBuyerName("");
//        // 发票代码
//        data.setInvoiceCode("");
//        //
//        data.setInvoiceStartDate("");
//        data.setInvoiceListMark("");
//        data.setSerialNo("");
//        data.setSourceMark("");
//        data.setInvoiceTypeCode("");
//        data.setInvoiceStatus("");
        request.setData(data);
        // request.setOrgCode("");
        request.setTaxNo(taxNo);

        // 初始化一个客户端
        IBWClient client = new BWRestClient(url, appKey, appSecret); // 初始化一个客户端
        OutputEinvoiceQueryResponse response = client.outputEinvoice().query(request, token);

        System.out.println("response："+response);

        return response;
    }

    public static void main(String[] args) {
        // TSalInvoice salInvoice = new TSalInvoice();
        System.out.println(exploReactivity("913101103124757262", "31"));
    }
}
